Skip to content

Persist latency/error history + fix Overview GPU strip for remote nodes - #42

Merged
Mapika merged 5 commits into
mainfrom
feature/metrics-persistence
Jun 5, 2026
Merged

Persist latency/error history + fix Overview GPU strip for remote nodes#42
Mapika merged 5 commits into
mainfrom
feature/metrics-persistence

Conversation

@Mapika

@Mapika Mapika commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Summary

Latency and errors on the Overview dashboard were live-only (a ~60s rolling window that died on restart). This persists them so they gain real multi-day history — and fixes a related GPU display bug for cluster setups.

  • Capture — a failure-isolated sink on the single RequestTracer.finalize chokepoint writes one request_metrics row per finalized request (migration 017). It captures all terminal outcomes, including pre-dispatch failures (bad model, auth, no-ready-service), so the error rate is complete. Sink errors are caught and logged, never breaking request serving.
  • Storage (hybrid) — raw rows (~48h) for exact recent percentiles + drill-down, plus an hourly rollup (request_metrics_hourly) with exact per-bucket percentiles computed at rollup time, retained retention_days. MetricsRollupTask mirrors UsageRollupTask.
  • APIGET /admin/metrics/history (per-bucket p50/p95 + error rate, raw for short windows / rollup for long, group_by=model|route, summary variant). All SQL literal (Bandit-clean).
  • Overview UI — latency/error tiles now read 24h history (badged 24h), plus a latency/error over-time chart (p95 bars + error-rate strip) and a per-model latency/error breakdown.
  • GPU health-strip fix — the strip now sources GPUs from the cluster metrics snapshot (nodes[].gpus[]) grouped by node, so a GPU-less leader (VPS) shows remote worker-node GPUs; falls back to local topology only when the snapshot has none. Extracted a shared GpuMeter.

Design/plan: docs/superpowers/specs/2026-06-05-metrics-persistence-design.md (local, gitignored).

Test Plan

  • Backend: 776 unit tests pass (16 new — sink, raw store, history/summary, hourly rollup + task, /admin/metrics/history). ruff + mypy + bandit clean.
  • Frontend: tsc -b + vite build green.
  • End-to-end on an isolated daemon seeded with realistic request_metrics (dispatched + pre-dispatch errors, two models): history/summary/group_by endpoints correct (400 dispatched + 12 pre-dispatch captured; per-model p95 distinguishes a slow model); Overview tiles show 24h numbers, chart + breakdown render, GPU strip renders from the snapshot. Zero browser console errors.
  • Reviewer: confirm the multi-node GPU grouping (node-label headers) on a real VPS-leader + remote-GPU-node setup — couldn't attach a remote agent in the e2e, so that specific grouping path is type-checked/unit-covered but not exercised live.

🤖 Generated with Claude Code

Mapika and others added 5 commits June 5, 2026 19:29
Migration 017 adds request_metrics (one row per finalized request) and
request_metrics_hourly (rollup). request_metrics.py provides record /
record_from_trace (the tracer sink) and history/summary queries with exact
per-bucket percentiles, optional group_by model|route. All SQL literal;
grouping keys are chosen in Python (no identifier interpolation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RequestTracer gains an optional on_finalize callback invoked once per
finalized request (the single chokepoint covering all terminal paths,
dispatched and pre-dispatch). build_app wires it to request_metrics so
every request's latency/status is persisted. Sink errors are caught and
logged, never breaking request serving.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
request_metrics_rollup folds aged raw rows into request_metrics_hourly with
exact per-bucket percentiles (all-models + per-model rows) and purges old
hourly rows. history/summary read raw for short windows and the rollup for
long windows. MetricsRollupTask (hourly) wired into app lifespan alongside
UsageRollupTask.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Read-only latency/error history: per-bucket p50/p95 + error rate (raw for
short windows, hourly rollup for long), optional group_by model|route, and a
summary variant for the tiles/breakdown. Validation mirrors /admin/usage/series.
api.ts gains getMetricsHistory/getMetricsSummary/getMetricsByModel + types.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Latency/errors tiles now read persisted history (/admin/metrics/history
summary, 24h) and are badged "24h" instead of "live · 60s". Add a
latency/errors over-time chart (p95 bars + error-rate strip) and a per-model
latency/error breakdown table.

Fix the GPU health strip to source GPUs from the cluster metrics snapshot
(nodes[].gpus[]) grouped by node, so a GPU-less leader (VPS) shows remote
worker-node GPUs; falls back to local topology only when the snapshot has
none. Extract a shared GpuMeter used by both paths. Header GPU count now
reflects the cluster total.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Mapika
Mapika merged commit a7390b7 into main Jun 5, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant